Overview

  • Hour 1
    • Curiousities from Assignment 2
      • Sets
    • Software Decomposition
    • Functions
    • Modules
    • Classes
  • Hour 2
    • Files
    • Emily
  • Hour 3
    • Graded lab

A curiousity from Assignment 2

  • The result of test cases changed when the order was changed
  • This shouldn't happen because:
    • Order shouldn't matter
    • The test cases are independent functions

Another curiousity

  • is_equal function in test file uses "set"
def is_equal(t1, t2):
    return set(map(tuple, t1)) == set(map(tuple, t2))

def is_equal(t1, t2):
    return sorted(t1) == sorted(t2)

In [56]:
list1 = [["a", "b", "c"], [1, 2, 3]]

# print tuple(["a", "b", "c"])
# print tuple([1, 2, 3])

map(tuple, list1)

for item in list1:
    tuple(item)


(['a', 'b', 'c'], [1, 2, 3])

In [61]:
table1 = [["a", "b", "c"], [1, 2, 3]]
table2 = [["a", "b", "c"], [1, 2, 3]]
table3 = [["a", "b", "c"], [1, 2, 4]]
table4 = [[1, 2, 3], ["a", "b", "c"]]

# list.sort()
# sorted(list)

def is_equal(t1, t2):    
    t1.sort()
    t2.sort()
    return t1 == t2

Sets

A set is a collection data structures that holds unique values. It works like a mathematical set.

Properties of Mathematical Sets

  • All elements in a set must be unique. No two elements have the same value.
  • Sets are unordered.
  • Elements in sets can be of different data types

In [ ]:
# Create a set
one_set = set()

In [58]:
# Constructor takes a single argument that is an iterable
another_set = set('aaabcc')

print(another_set)


set(['a', 'c', 'b'])

Problem

  • set() removes duplicates
  • Not useful for situations where we are testing if duplicates have been removed

We'll need a different is_equal function


In [ ]:

Software Decomposition

We break up code into smaller chunks to make it more manageable and easier to understand.

Benefits

  • Hides information
  • Chunks lines into concepts
  • Organize similar concepts together
  • Creates smaller scopes
  • Reuse

Language Features

  • Functions
  • Modules
  • Classes

Modules

A module is a file that contain Python code. Large programs are easier to debug and maintain when they are divided into modules.

We have already been using this feature. Each exercise is a module. Test modules import program modules

Naming Modules

  • Must end in .py
  • Must not be a Python keyword

Import

  • Access the contents of another module using import. It's like reading it into memory.
  • Put these statements at the top of the file, one per line

Example

Suppose you have been asked to write a program that calculates the following.

  • Area of a circle
  • Circumference of a circle
  • Area of a rectangle
  • Perimeter of a rectangle

What modules would you create? What functions would you create?

Functions

  • A function is a way to group together lines of code.
  • Useful for doing the same task in different places.
  • Makes the code easier to read.
  • Avoids repeating code.
def function_name():
    statement
    statement
    statement
  • A function has the following parts.
    • A name
    • Parameters (inputs)
    • Optionally, return values (outputs)

Functions are either a void function or a value-returning function.


In [ ]:
# Turn this code into a function

def what_to_wear(temperature):
    output = ""
    
    if (temperature < 15):
        output = "Wear a coat."
    
    return output

what_to_wear(8)

Designing a Program to Use Functions

When we design a program, we have to plan ahead to use functions effectively. Taking a problem or program and breaking it into sub-parts is calle top-down design.

Steps in Top-Down Design

  1. The overall task is broken into sub-tasks.
  2. Each sub-task is examined to determine whether it can be broken down further. Repeat until no more sub-tasks can be identified.
  3. Once all the sub-tasks are identified, they are written in code.

IPO Chart

  • IPO stands for input, processing, and output.

Hierarchy Chart

Useful for displaying calls to function


In [63]:
def get_hourly_rate():
    print ("get_hourly_rate")

def get_hours_worked():
    print ("get_hours_worked")

def get_input():
    print ("get_input")
    get_hours_worked()
    get_hourly_rate()

def main():
    print("main")
    get_input()
    
main()


main
get_input
get_hours_worked
get_hourly_rate

Example

  • Lab 3 where we used a function to get and check input from keyboard
    • Input function only checked for integer, not for permitted values
    • Separation of concerns

When to Add a Function

  • Section of code becomes too long
  • Functionality is reused

Naming Functions

  • Verb phrase

Objects

  • Objects are created from abstract data types that encapsulate data and functionality together.
  • Idea: Objects, or data representations, are more stable than functionality.
  • Also called encapsulation

  • Information hiding
  • Object reusability

Functions attached to an object are called methods.

Example

Your alarm clock as a software object. It would have the following data attributes.

  • current_second (a value in the range 0-59)
  • current_minute (a value in the range 0-59)
  • current_hour (a value in the range 0-12)
  • alarm_time (a valid hour and minute)
  • alarm_is_set (True or False)

These attributes define the state of the alarm clock.

These attributes are private, meaning you can't change them.

But you can use public methods (buttons) to change them.

  • set_time
  • set_alarm_time
  • set_alarm_on
  • set_alarm_off

There are private methods that are part of the clock's internal workings.

  • increment_current_second
  • increment_current_minute
  • increment_current_hour
  • sound_alarm

We have already been using objects, specifically the MismatchedAttributesException in Exercise 3 of Assignment 2.

Class

  • A class is the code that specifies the data attributes and methods for a particular type of object.
  • They are like blueprints or cookie cutters

Naming

  • Nouns
  • Capitalize first letter

In [65]:
import random

# The Coin class simulates a coin that can be flipped

class Coin:
    # The __init__ methods is the constructor
    
    def __init__(self):
        self.sideup = 'Heads'
    
    def toss(self):
        flip = random.randint(0, 1)
        if flip == 0:
            self.sideup = "Heads"
        else:
            self.sideup = "Tails"
    
    def get_sideup(self):
        return self.sideup

In [66]:
def main():
    my_coin = Coin()
    
    print("This side is up: " + my_coin.get_sideup())
    
    print("I am tossing the coin...")
    my_coin.toss()
    
    print("This side is up: " + my_coin.get_sideup())

In [70]:
main()


This side is up: Heads
I am tossing the coin...
This side is up: Tails

In [72]:
for _ in range(5):
   print random.randint(0, 1)


0
0
1
0
0

File Input and Output

  • Files store data for later use.
  • Writing to a disk saves data from memory in a file.
  • Reading from a disk gets data from a file and puts it into memory.

Encodings

  • A bit is a binary digit. It can have a value of 0 or 1. There are 8 bits in 1 byte.
  • Text encodings, such as ASCII or unicode, can be read by humans. Non-text encodings are used for images, audio, executables, etc.
  • ASCII is an 7-bit encoding for representing Latinate characters and control codes (like \n). Since it is 7 bits, it can represent 2^7 or 128 characters.
  • It has since been succeeded, but not replaced, by Unicode (a character set) encoded in 8, 16, or 32 bits. This format can be used to represent over 113 000 glyphs from a variety of alphabets.

Opening a file

To start using a file, given its filename, you have to open it. But first, the name— a string. How we get that string depends on our needs. Here are a few options.

  • Have the user to enter the name using the input() function.
  • Have user to select it from a list presented by the interface.
  • Store the name in a configuration file
  • Hard code the string in the program

Once we have the filename, we need to turn it into something that the Python program can work with. This involves creating a file handle or file object, by opening the file.


In [73]:
with open("jabberwocky.txt", "r") as file_reader:
    # insert file operation here
    file_contents = file_reader.read()

print file_contents


`Twas brillig, and the slithy toves
  Did gyre and gimble in the wabe:
All mimsy were the borogoves,
  And the mome raths outgrabe.

"Beware the Jabberwock, my son!
  The jaws that bite, the claws that catch!
Beware the Jubjub bird, and shun
  The frumious Bandersnatch!"
He took his vorpal sword in hand:
  Long time the manxome foe he sought --
So rested he by the Tumtum tree,
  And stood awhile in thought.
And, as in uffish thought he stood,
  The Jabberwock, with eyes of flame,
Came whiffling through the tulgey wood,
  And burbled as it came!
One, two! One, two! And through and through
  The vorpal blade went snicker-snack!
He left it dead, and with its head
  He went galumphing back.
"And, has thou slain the Jabberwock?
  Come to my arms, my beamish boy!
O frabjous day! Callooh! Callay!'
  He chortled in his joy.

`Twas brillig, and the slithy toves
  Did gyre and gimble in the wabe;
All mimsy were the borogoves,
  And the mome raths outgrabe.

  • with is a Python keyword that automatically calls certain functions before and after the statement
  • open is a Python function
  • jabberwocky.txt is the name of the file to be opened
  • file reader is a variable that is assigned the file object (or “stream” or “reader”/“writer”) returned by open
  • "r" is a string indicating what we wish to do with the file.
    • Options for this string are "r", "w", "a", meaning read, write or append. The default is "r".
    • If you write to a file that already exists, the old contents are erased. If you append, the new content is added to the end of the file.

What 'with' does for us

When opening a file, there are some things that can go wrong. The file might not exist. The program might not have permission to access the file. There might be a hardware error that occurs during access. For these reasons, file reading usually occurs after some checking or within a try-except block.

Once we are done accessing the file, we have to close it. The contents aren’t actually saved to disk until we close it. Closing the file also reduces the resources used by our program and makes the file available for others to access.

If we didn't have "with", here's what the code would look like.


In [46]:
file_name = "jabberwocky.txt"

try:
    file_reader = open(file_name)
    # file read operation goes here
except(OSError, IOError):
    print("Error reading file: " + file_name)
else:
    s = file_reader.read()
    file_reader.close()

Reading from a file

Now that we have a file handle or reader, we can get the contents. There are five ways to read from a basic file handle.


In [75]:
file_name = "jabberwocky.txt"

In [47]:
# All at once into a string

with open(file_name) as file_reader:
    file_contents = file_reader.read()

In [ ]:
# All at once into a list

with open(file_name) as file_reader:
    file_contents = file_reader.readlines()

In [ ]:
# All lines, one at a time

with open(file_name) as file_reader:
    for line in file_reader:
        print (line),
  • Why is the output double spaced?
  • How can we single space the output?

In [81]:
# One line at a time
with open(file_name) as file_reader:
    line = file_reader.readline()
    print(line)
    line= file_reader.readline()
    print(line)
    line = file_reader.readline()
    print(line)


`Twas brillig, and the slithy toves

  Did gyre and gimble in the wabe:

All mimsy were the borogoves,

  • When would you use this instead of a for loop?

In [ ]:
# By groups of characters
with open(file_name) as file_reader:
    input_group = file_reader.read(10)   # Read 10 characters
    print(input_group)
    input_group = file_reader.read(10)   # Read the next 10 characters
    print(input_group)

Advantages and Disadvantages

Dealing with "end of file"

Unless you choose to stop reading, you will eventually reach the end of an input file, called “EOF”. The the first three approaches automatically recognizes EOF. With the remaining two, you have to detect the situation of being at EOF yourself.

If you are at EOF, when you call read() or readline() you get an empty string.

Note: An empty string is not the same as a blank line.


In [ ]:
# Open a file called filename and read line by line until EOF is reached

Writing to a file

First, we open a file to write, using the same "with" construction

Then we write the contents.


In [82]:
file_name = "missive.txt"

with open(file_name, 'w') as output_file:
    output_file.write("Dear Uncle Marty,\n")
    output_file.write("Thanks for the nifty present.\n")
    output_file.write("Love,\nYour Niece\n")
  • Until you close, Python may save up the text for later output.
    • Examine missive.txt before you close it; it’s probably empty.

In [83]:
output_file = open(file_name, 'w')
output_file.write("Dear Uncle Marty,\n")
output_file.write("Thanks for the nifty present.\n")
output_file.write("Love,\nYour Niece\n")

kb_hit = raw_input("waiting...")
output_file.close()

In [ ]: